#include "sntp_api.h"

static const char *TAG = "sntp";
void local_time_add_year(struct tm *time)
{
    time->tm_year++;
    if (time->tm_year >= 2099)
    {
        time->tm_year = 1995;
    }
}
void local_time_add_month(struct tm *time)
{
    time->tm_mon++;
    if (time->tm_mon > 12)
    {
        time->tm_mon = 1;
    }
}
void local_time_add_day(struct tm *time)
{
    time->tm_mday++;
    if (time->tm_mon == 1 || time->tm_mon == 3 || time->tm_mon == 5 
        || time->tm_mon == 7 || time->tm_mon == 8 || time->tm_mon == 10 || time->tm_mon == 12)
    {
        if (time->tm_mday > 31)
            time->tm_mday = 1;
    }
    else if (time->tm_mon == 2)
    {
        if ((time->tm_year % 4 == 0 && time->tm_year % 100 != 0) || time->tm_year % 400 == 0)
        {
            if (time->tm_mday > 29)
            {
                time->tm_mday = 1;
            }
        }
        else
        {
            if (time->tm_mday > 28)
            {
                time->tm_mday = 1;
            }
        }
    }
    else
    {
        if (time->tm_mday > 30)
            time->tm_mday = 1;
    }
}
void local_time_add_hour(struct tm *time)
{
    time->tm_hour++;
    if (time->tm_hour > 23)
    {
        time->tm_hour = 0;
    }
}
void local_time_add_min(struct tm *time)
{
    time->tm_min++;
    if (time->tm_min > 59)
    {
        time->tm_min = 0;
    }
}

uint32_t time_to_stamp(unsigned int year, unsigned int mon, unsigned int day, unsigned int hour, unsigned int min, unsigned int sec)
{
    if (0 >= (int)(mon -= 2))
    {
        mon += 12;
        year -= 1;
    }
    return ((((unsigned long)(year / 4 - year / 100 + year / 400 + 367 * mon / 12 + day) + year * 365 - 719499) * 24 + hour) * 60 + min) * 60 + sec;
}

static void alarm_task(void *arg)
{
    mtime.tstamp_to_ltime();

    while ((mtime.g_alarm[0].tm_min == mtime.g_time.tm_min))
    {
        ESP_LOGI(TAG, "==tag:%d\n", mtime.g_alarm_ring);
        tone.alarm_tone();
        delay_ms(70);
        mtime.tstamp_to_ltime();
        if (mtime.g_alarm_ring == 1)
            break;
    }
    ESP_LOGI(TAG, "==== OUT ====\n");
    mtime.add_alarm();
    vTaskDelete(NULL);
}

/************************************************/
void mysntp_init(void);
static void timestamp_to_localtime(void);
static void localtime_to_timestamp(void);
static void alarm_create(void);
static void alarm_delete(void);
Mtime mtime = {
    .msntp_init = mysntp_init,
    .tstamp_to_ltime = timestamp_to_localtime,
    .ltime_to_tstamp = localtime_to_timestamp,
    .add_alarm = alarm_create,
    .delete_alarm = alarm_delete,
};

/* =========== alarm =========== */
/*********************************************************************
 *  名称： alarm_scan
 *  功能： 闹钟扫描
 *  参数： void
 *  返回值：void
 ********************************************************************/
static void alarm_scan(void *args)
{
    mtime.tstamp_to_ltime();
    if(mtime.g_alarm[0].tm_hour == mtime.g_time.tm_hour
        && mtime.g_alarm[0].tm_min == mtime.g_time.tm_min)
    {
        mtime.delete_alarm();
        //任务
        if (mtime.g_alarm_ring == 0)
        {
            xTaskCreate(alarm_task, "alarm_task", 1024, NULL, 10, NULL);
        }
    }
}

static void alarm_create(void)
{
    if (Dsystem.sys_alarm_en)
    {
        mtime.g_alarm_ring = 0;
        os_timer_disarm(&time_alarmScan_20000ms);
        os_timer_setfn(&time_alarmScan_20000ms, (os_timer_func_t *)alarm_scan, 0);
        os_timer_arm(&time_alarmScan_20000ms, 10000, 1);
    }
}

static void alarm_delete(void)
{
    os_timer_disarm(&time_alarmScan_20000ms);
}

/* time */
static void localtime_to_timestamp(void)
{
    if (0 >= (int)(mtime.g_time.tm_mon -= 2))
    {
        mtime.g_time.tm_mon += 12;
        mtime.g_time.tm_year -= 1;
    }
    mtime.g_timestamp = ((((unsigned long)(mtime.g_time.tm_year / 4 - mtime.g_time.tm_year / 100 + mtime.g_time.tm_year / 400 + 367 * mtime.g_time.tm_mon / 12 + mtime.g_time.tm_mday) + mtime.g_time.tm_year * 365 - 719499) * 24 + mtime.g_time.tm_hour) * 60 + mtime.g_time.tm_min) * 60 + mtime.g_time.tm_sec;
    if (mtime.g_time.tm_year >= 2020)
        mtime.g_timestamp -= 8 * 60 * 60;
}

static void timestamp_to_localtime(void)
{
    char strftime_buf[64] = {0};

    mtime.g_time = *localtime(&mtime.g_timestamp);
    strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &mtime.g_time);
    mtime.g_time.tm_year = atoi(strftime_buf);
    mtime.g_time.tm_mon = atoi(strftime_buf + 5);
    mtime.g_time.tm_mday = atoi(strftime_buf + 8);
    mtime.g_time.tm_hour = atoi(strftime_buf + 11);
    mtime.g_time.tm_min = atoi(strftime_buf + 14);
    mtime.g_time.tm_sec = atoi(strftime_buf + 17);
}

static void initialize_sntp(void)
{
    ESP_LOGI(TAG, "Initializing SNTP");
    sntp_setoperatingmode(SNTP_OPMODE_POLL);
    sntp_setservername(0, "pool.ntp.org");
    sntp_init();
}

static void obtain_time(void)
{
    initialize_sntp();
    uint8_t retry = 0;
    // wait for time to be set
    time_t now = 0;
    struct tm timeinfo = {0};

    const int retry_count = 10;

    while (timeinfo.tm_year < (2016 - 1900))
    {
        retry++;
        if (retry > retry_count)
        {
            retry = 0;
            return;
        }
        ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
        vTaskDelay(2000 / portTICK_PERIOD_MS);
        time(&now);
        localtime_r(&now, &timeinfo);
    }
    mtime.sntp_syn = 1;
}

static void sntp_task(void *arg)
{
    time_t now;
    struct tm timeinfo;

    while (1)
    {
        ESP_LOGI(TAG, "== SNTP Waiting WIFI %d ==\n", wifi.wifi_status);
        if (wifi.wifi_status == SYS_WIFI_STATUS_CONNECT_ERR)
        {
            ESP_LOGI(TAG, "== DELETE SNTP TASK: out time ==\n");
            vTaskDelete(NULL);
            mtime.sntp_syn = 0;
            return;
        }
        else if (wifi.wifi_status == SYS_WIFI_STATUS_CONNECTED)
        {
            break;
        }
        delay_ms(1000);
    }

    time(&now);
    localtime_r(&now, &timeinfo);

    // Is time set? If not, tm_year will be (1970 - 1900).
    if (timeinfo.tm_year < (2020 - 1900))
    {
        ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
        obtain_time();
    }
    time(&now);
    mtime.g_timestamp = now;
    setenv("TZ", "CST-8", 1);
    tzset();
    ESP_LOGI(TAG, "== DELETE SNTP TASK: ok,over ==\n");

    weather.weather_syn = 1;
    if (weather.weather_syn == 1 && Dsystem.sys_wifi_enable == 1)
    {
        Dsystem.sys_wifi_enable = 0;
        wifi.close_wifi();
    }
    vTaskDelete(NULL);
}

void mysntp_init(void)
{
    if (Dsystem.sys_sntp_en)
    {
        ESP_LOGI(TAG, "== SNTP TASK INIT ==\n");
        xTaskCreate(sntp_task, "sntp_task", 2048, NULL, 10, NULL);
    }
}